/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.vojna.ant_alg.algorithms;

import pl.vojna.ant_alg.Algorithm;
import pl.vojna.ant_alg.PbbFunction;
import pl.vojna.ant_alg.Problem;
import pl.vojna.ant_alg.Utils;

/**
 *
 * @author rusak
 */
public class MMAntSystem implements Algorithm {

    double pheromoneVanish;
    double pheromoneStrength;
    double minPheromone, maxPheromone;
    protected int[] bestSol;
    public MMAntSystem(double pheromoneVanish, double pheromoneStrength, double minPheromone, double maxPheromone) {
        this.pheromoneVanish = pheromoneVanish;
        this.pheromoneStrength = pheromoneStrength;
        this.minPheromone = minPheromone;
        this.maxPheromone = maxPheromone;
    }

    protected double[][] initPhereomone(int problemSize) {
        final double pheromoneTrails[][] = new double[problemSize][problemSize];
        for (int i = 0; i < problemSize; i++) {
            for (int j = 0; j < problemSize; j++) {
                pheromoneTrails[i][j] = minPheromone;
            }
        }
        return pheromoneTrails;
    }

    public Ant[] results(Problem problem, int popSize, Boolean isDebug,
            final double pheromoneTrails[][]) {
        int bestIndex = 0;
        int antSize = problem.getSize();

        Ant population[] = new Ant[popSize];

        for (int i = 0; i < popSize; i++) {
            population[i] = new Ant(antSize, problem, new PbbFunction() {

                @Override
                public double call(int i, int j) {
                    return pheromoneTrails[i][j];
                }
            });
        }

        int assignedInThisStep[][] = new int[popSize][2];

        for (int i = 0; i < antSize; i++) {
            if (isDebug) {
                System.out.println("STEP: " + i);
            }


            if (isDebug) {
                System.out.print("PHEROMONE TRAILS: "
                        + Utils.showArray(pheromoneTrails));
            }
            for (int j = 0; j < popSize; j++) {
                assignedInThisStep[j] = population[j].nextStep(pheromoneTrails);
                if (isDebug) {
                    System.out.println("ANT " + j + ":");
                    Utils.showSolution(population[j].getSolution());
                }
            }



        }
        bestSol = population[0].getSolution();
        int pretender[];
        double pretenderCost;


        double bestCost = Utils.solutionCost(problem, bestSol);
        for (int z = 1; z < popSize; z++) {
            pretender = population[z].getSolution();
            pretenderCost = Utils.solutionCost(problem, pretender);
            if (pretenderCost < bestCost) {
                bestSol = pretender;
                bestIndex = z;
                bestCost = pretenderCost;
            }
        }


        int[] bestAntSol = population[bestIndex].getSolution();

        for (int z = 0; z < antSize; z++) {
            pheromoneTrails[z][bestAntSol[z]] += (pheromoneStrength / population[bestIndex].getCost());
        }
        return population;

    }

    @Override
    public int[] solve(Problem problem, int popSize, Boolean isDebug, int noIterations) {
        int antSize = problem.getSize();
        final double pheromoneTrails[][] = initPhereomone(antSize);

        int best[] = null;
        double bestCost = -1;
        for (int k = 0; k < noIterations; k++) {
            
            Ant[] population = results(problem, popSize, isDebug,
                    pheromoneTrails);

            if (k == 0) {
                best = bestSol;
                bestCost = Utils.solutionCost(problem, best);
            }
            double pretCost;
            if (bestCost > (pretCost = Utils.solutionCost(problem, bestSol))) {
                best = bestSol;
                bestCost = pretCost;
            }
            vanishPheromone(pheromoneTrails);



        }

        return best;
    }

    private void vanishPheromone(double pheromoneTrails[][]) {
        int size = pheromoneTrails.length;
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                pheromoneTrails[i][j] *= (1 - pheromoneVanish);
                if (pheromoneTrails[i][j] < minPheromone) {
                    pheromoneTrails[i][j] = minPheromone;
                } else if (pheromoneTrails[i][j] > maxPheromone) {
                    pheromoneTrails[i][j] = maxPheromone;
                }
            }
        }

    }
}
